<template>
  <div class="img-gird-upload">
    <div class="img-gird-upload-btns" v-if="fileLimit > 1">
      <a-radio-group>
        <a-button type="link" @click="onAdd" style="padding-left: 0;">
          <template #icon>
            <component :is="$Icon['PlusOutlined']"></component>
          </template>
          添加
        </a-button>
        <a-button type="link" @click="onReset">
          <template #icon>
            <component :is="$Icon['RedoOutlined']"></component>
          </template>
          重置
        </a-button>
      </a-radio-group>
      <div class="img-gird-upload-tip ant-typography ant-typography-secondary">最多可以添加{{ fileLimit }}张图片</div>
    </div>
    <div class="img-gird-upload-content">
      <draggable v-model="imgs" tag="ul" :sort="true" animation="300" handle=".img-gird-upload-list-header"
        :class="['img-gird-upload-list']" @end="onSortEnd">
        <template #item="{ element, index }">
          <li @mouseenter="onSenter(index)" @mouseleave="onleavue(index)">
            <transition name="fade-in-down">
              <div class="img-gird-upload-list-header" v-if="allowSort && fileLimit > 1" v-show="element.showTools">
                <i class="icon icon-tuodong"></i>
                拖动排序
              </div>
            </transition>
            <div class="img-gird-upload-list-content">
              <img :src="element.src" :style="style" />
            </div>
            <transition name="fade-in-up">
              <div class="img-gird-upload-list-footer" v-show="element.showTools">
                <div @click="onEdit(index)">
                  <a-button type="link" block title="修改">
                    <template #icon>
                      <component :is="$Icon['FormOutlined']"></component>
                    </template>
                  </a-button>
                </div>
                <div @click="onDelete(index)">
                  <a-button type="link" block title="删除">
                    <template #icon>
                      <component :is="$Icon['DeleteOutlined']"></component>
                    </template>
                  </a-button>
                </div>
              </div>
            </transition>
          </li>
        </template>
      </draggable>
      <div class="ant-typography ant-typography-secondary img-gird-upload-tip" v-show="!checkfileExist">
        <exclamation-circle-outlined /> 你还未上传任何文件
      </div>
      <div class="ant-typography ant-typography-secondary img-gird-upload-tip" v-if="helpText != ''">{{ helpText }}
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import {
  ref,
  getCurrentInstance,
  toRaw,
  watch
} from "vue";
import { Modal } from "ant-design-vue";
import draggable from 'vuedraggable';

import emptyImageSrc from '@/assets/empty_image.svg'

/**
 * 参数
 */
interface IProps {
  /**
   * 图片地址 以,分割的  img,img1.img2
   */
  modelValue: string

  /**
   * 图片宽度
   */
  width?: number;

  /**
   * 图片高度
   */
  height?: number;

  /**
   * 允许排序
   */
  allowSort?: boolean;

  /**
   * 最大上传文件数量
   */
  fileLimit?: number;

  /**
   * 最大文件大小
   */
  fileSize?: number;
  /**
   * 帮助描述信息
   */
  helpText?: string;

  /**
   * 显示图片圆角大小 比如 10px 
   */
  borderRadius?: number;

  /**
   * 设置默认空图片地址
   */
  emptyImage?: string;
}

/**
 * 显示的图片数据
 */
interface IImg {
  /**
   * 访问地址
   */
  src: string;

  /**
   * 是否显示操作工具
   */
  showTools: boolean;

  /**
   * 是否是空图片 单个默认图片需要判断
   */
  emptyImage: boolean;
}

const props = withDefaults(defineProps<IProps>(), {
  width: 160,
  height: 160,
  allowSort: true,
  fileLimit: 1,
  fileSize: 300 * 1024,
  helpText: "",
  borderRadius: 0,
  emptyImage: emptyImageSrc
})


let asyncLock = false; //防止异步传值无法赋值，以及数据监听重复触发问题

const emits = defineEmits(["update:modelValue"]);
const imgs = ref<IImg[]>([]);

const checkfileExist = ref(false); //检查是否真实存在文件 增加提示

const proxy: any = getCurrentInstance()?.proxy;
const style: any =
{
  width: `${props.width}px`,
  height: `${props.height}px`,
  'border-radius': `${props.borderRadius}px`,
};

//初始化数据
const initData = (imgSrc: string) => {
  if (imgSrc == "" || imgSrc == null || imgSrc === undefined) {
    asyncLock = true;
    return;
  }
  if (props.fileLimit == 1 && imgSrc == "") {
    imgs.value.push({
      src: props.emptyImage,
      showTools: false,
      emptyImage: true
    });
  } else {
    imgSrc.split(',').forEach(img => {
      imgs.value.push({
        src: img,
        showTools: false,
        emptyImage: false
      });
    })
  }
  checkfileExist.value = true;

};

//初始化值
initData(props.modelValue);

//监听值改变
watch(() => props.modelValue, (newValue) => {
  if (asyncLock) {
    initData(newValue);
    asyncLock = false;
  }
})

//添加图片
const onAdd = () => {
  var leng = imgs.value.filter(f => !f.emptyImage).length;
  if (leng >= props.fileLimit) {
    Modal.error({ content: `最多只能添加 ${props.fileLimit} 张图片` });
    return;
  }
  //计算剩下数量
  var mult = props.fileLimit - leng;
  proxy.$FileUpload({
    fileSize: props.fileSize,
    fileNum: mult
  }, (url: string[]) => {
    url.forEach(_url => {
      let item: IImg = {
        src: _url,
        showTools: false,
        emptyImage: false
      };
      imgs.value.push(item);
      asyncLock = false;
      onEmitUpdate();
    })
  })
};

//重置图片
const onReset = () => {
  imgs.value = [];
  onEmitUpdate();
};

//修改指定图片
const onEdit = (index: number) => {
  proxy.$FileUpload({
    fileSize: props.fileSize
  }, (url: string[]) => {
    let item: IImg = {
      src: url[0],
      showTools: false,
      emptyImage: false
    };
    imgs.value.splice(index, 1, item);
    imgs.value[index].emptyImage = false;
    asyncLock = false;
    onEmitUpdate();
  })
};

//删除
const onDelete = (index: number) => {
  if (props.fileLimit == 1) {
    imgs.value[index].src = props.emptyImage;
    imgs.value[index].emptyImage = true;
  } else {
    imgs.value.splice(index, 1);
  }
  onEmitUpdate();
};

//鼠标进入
const onSenter = (i: number) => {
  imgs.value[i].showTools = true;
};

//鼠标离开
const onleavue = (i: number) => {
  imgs.value[i].showTools = false;
};


//排序结束
const onSortEnd = () => {
  onEmitUpdate();
}

//触发emit事件
const onEmitUpdate = () => {
  let newValue = toRaw(imgs.value).filter(f => !f.emptyImage);
  let srcs = newValue.map(m => m.src).join(',');
  checkfileExist.value = newValue.length > 0;
  emits("update:modelValue", srcs);
}

</script>

<style scoped>
.img-gird-upload {
  background-color: #fff;
}

.img-gird-upload-btns {
  margin-bottom: 10px;
}

.app-content {
  top: 56px;
}

.img-gird-upload-default-image>div {
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  background-image: url(https://cmp520.oss-cn-shenzhen.aliyuncs.com/default/empty.jpg);
  background-size: 100% 100%;
}

.img-gird-upload-list {
  padding: 0;
  margin: 0;
}

.img-gird-upload-list>li {
  position: relative;
  display: inline-block;
  margin: 0px 10px 10px 0px;
}

.img-gird-upload-list-header {
  position: absolute;
  left: 0;
  top: 0px;
  width: 100%;
  display: flex;
  display: block;
  color: #fff;
  text-align: center;
  cursor: move;
  background-color: rgba(0, 0, 0, 0.2);
}

.img-gird-upload-list-header:hover {
  background-color: rgba(0, 0, 0, 0.5);
  transition: all 0.5s;
}

.img-gird-upload-list-content>img {
  display: block;
  width: 120px;
}

.img-gird-upload-list-footer {
  position: absolute;
  bottom: 0px;
  left: 0;
  width: 100%;
  display: flex;
  background-color: rgba(0, 0, 0, 0.2);
}

.img-gird-upload-list-footer button {
  color: #fff;
}

.img-gird-upload-list-footer>div {
  flex: 1;
  /* padding: 3px 1px 0px 0px; */
}

.img-gird-upload-tip {
  padding-top: 3px;
}

.img-gird-upload-list-footer>div:hover {
  background-color: rgba(0, 0, 0, 0.5);
  transition: all 0.5s;
}

.fade-in-up-enter-active {
  animation: fadeInUp 0.1s 0.1s ease both;
}

@keyframes fadeInUp {
  0% {
    opacity: 0;
    transform: translateY(3px);
  }

  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.fade-in-down-enter-active {
  animation: fadeInDown 0.1s 0.1s ease both;
}

@keyframes fadeInDown {
  0% {
    opacity: 0;
    transform: translateY(-3px);
  }

  100% {
    opacity: 1;
    transform: translateY(0);
  }
}
</style>
